package com.hunttown.mes.common.qcloud.qcloudcos;

import com.hunttown.mes.common.utils.StringUtils;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * created by wangjunfu on 2020-06-13
 */
public class CosUtils {

    /**
     * 获取客户端
     * 每次请求都会创建，比较频繁
     *
     * @param secretId  腾讯云COS的secretId
     * @param secretKey 腾讯云COS的secretKey
     * @param region    腾讯云COS存储地区
     * @return COSClient
     */
    private static COSClient getCosClient(String secretId, String secretKey, String region) {
        //1.初始化用户身份信息（secretId, secretKey）。
        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);

        //2.设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224
        //clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分。
        Region regionobj = new Region(region);
        ClientConfig clientConfig = new ClientConfig(regionobj);

        //3.生成 cos 客户端。
        return new COSClient(cred, clientConfig);
    }

    /**
     * 创建桶
     *
     * @param secretId  腾讯云COS的secretId
     * @param secretKey 腾讯云COS的secretKey
     * @param region    腾讯云COS存储地区
     * @param bucket    要创建的桶名称
     * @return 结果
     */
    public static Boolean createBucket(String secretId, String secretKey, String region, String bucket) {

        if (StringUtils.isBlank(bucket)) {
            return false;
        }

        //存储桶名称，格式：BucketName-APPID
        CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucket);

        //设置 bucket 的权限：Private(私有读写), PublicRead(公有读私有写), PublicReadWrite(公有读写)
        createBucketRequest.setCannedAcl(CannedAccessControlList.PublicRead);

        try {
            COSClient cosClient = getCosClient(secretId, secretKey, region);
            Bucket bucketResult = cosClient.createBucket(createBucketRequest);
            return bucketResult != null;

        } catch (CosClientException serverException) {
            serverException.printStackTrace();
        }

        return false;
    }

    /**
     * 查询存储桶
     *
     * @param secretId  腾讯云COS的secretId
     * @param secretKey 腾讯云COS的secretKey
     * @param region    腾讯云COS存储地区
     * @return 桶名称列表
     */
    public static List<String> getBucket(String secretId, String secretKey, String region) {
        COSClient cosClient = getCosClient(secretId, secretKey, region);
        List<Bucket> buckets = cosClient.listBuckets();

        List<String> bucketList = new ArrayList<>();
        for (Bucket bucketElement : buckets) {
            bucketList.add(bucketElement.getName());
        }

        return bucketList;
    }

    /**
     * 上传对象（路径）
     *
     * @param secretId  腾讯云COS的secretId
     * @param secretKey 腾讯云COS的secretKey
     * @param region    腾讯云COS存储地区
     * @param bucket    指定要上传到的存储桶
     * @param filePath  要上传的文件
     * @param onlySign  对象在存储桶中的唯一标识
     * @return etag
     */
    public static String uploadCos(String secretId, String secretKey, String region, String bucket, String filePath, String onlySign) {

        //适用于20M以下图片类小文件上传，最大支持上传不超过5GB文件。5GB以上的文件必须使用分块上传或高级 API 接口上传。
        //指定要上传的文件
        File localFile = new File(filePath);

        //指定要上传到 COS 上对象键
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, onlySign, localFile);

        //设置存储类型, 默认是标准(Standard), 低频(standard_ia)
        putObjectRequest.setStorageClass(StorageClass.Standard_IA);

        COSClient cosClient = getCosClient(secretId, secretKey, region);
        PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
        String etag = putObjectResult.getETag();

        return etag;
    }

    /**
     * 上传对象（输入流）
     *
     * @param secretId  腾讯云COS的secretId
     * @param secretKey 腾讯云COS的secretKey
     * @param region    腾讯云COS存储地区
     * @param bucket    指定要上传到的存储桶
     * @param file      输入流文件
     * @param onlySign  对象在存储桶中的唯一标识
     * @return etag
     */
    public static String uploadCos(String secretId, String secretKey, String region, String bucket, MultipartFile file, String onlySign) {

        InputStream input = null;

        try {
            input = file.getInputStream();

            ObjectMetadata objectMetadata = new ObjectMetadata();

            //从输入流上传必须制定content length, 否则http客户端可能会缓存所有数据，存在内存OOM的情况
            //objectMetadata.setContentLength(file.getSize());  //size和下面的available的效果一样。
            objectMetadata.setContentLength(input.available());

            //默认下载时根据cos路径key的后缀返回响应的contenttype, 上传时设置contenttype会覆盖默认值
            objectMetadata.setContentType(file.getContentType());

            //指定要上传到 COS 上对象键
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucket, onlySign, input, objectMetadata);

            //设置存储类型, 默认是标准(Standard), 低频(standard_ia)
            putObjectRequest.setStorageClass(StorageClass.Standard_IA);

            COSClient cosClient = getCosClient(secretId, secretKey, region);
            PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
            String etag = putObjectResult.getETag();

            return etag;

        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 查询对象列表
     *
     * @param secretId  腾讯云COS的secretId
     * @param secretKey 腾讯云COS的secretKey
     * @param region    腾讯云COS存储地区
     * @param bucket    要查询的存储桶
     * @param prefix    表示对象的key以prefix开始，如："images/"
     * @return 对象key列表
     */
    public static List<String> getCosList(String secretId, String secretKey, String region, String bucket, String prefix) {

        // Bucket的命名格式为 BucketName-APPID ，此处填写的存储桶名称必须为此格式
        ListObjectsRequest listObjectsRequest = new ListObjectsRequest();

        // 设置bucket名称
        listObjectsRequest.setBucketName(bucket);

        // prefix表示列出的object的key以prefix开始
        listObjectsRequest.setPrefix(prefix);

        // deliter表示分隔符, 设置为/表示列出当前目录下的object, 设置为空表示列出所有的object
        listObjectsRequest.setDelimiter("/");

        // 设置最大遍历出多少个对象, 一次listobject最大支持1000
        listObjectsRequest.setMaxKeys(1000);
        ObjectListing objectListing = null;

        List<String> cosList = new ArrayList<>();

        do {
            try {
                COSClient cosClient = getCosClient(secretId, secretKey, region);
                objectListing = cosClient.listObjects(listObjectsRequest);
            } catch (CosClientException e) {
                e.printStackTrace();
                return null;
            }

            // common prefix表示表示被delimiter截断的路径, 如delimter设置为/, common prefix则表示所有子目录的路径
            List<String> commonPrefixs = objectListing.getCommonPrefixes();

            // object summary表示所有列出的object列表
            List<COSObjectSummary> cosObjectSummaries = objectListing.getObjectSummaries();
            for (COSObjectSummary cosObjectSummary : cosObjectSummaries) {

                // 文件的路径key
                String key = cosObjectSummary.getKey();
                cosList.add(key);

                // 文件的etag
                //String etag = cosObjectSummary.getETag();

                // 文件的长度
                //Long fileSize = cosObjectSummary.getSize();

                // 文件的存储类型
                //String storageClasses = cosObjectSummary.getStorageClass();
            }

            String nextMarker = objectListing.getNextMarker();
            listObjectsRequest.setMarker(nextMarker);

        } while (objectListing.isTruncated());

        return cosList;
    }

    /**
     * 下载对象
     *
     * @param secretId  腾讯云COS的secretId
     * @param secretKey 腾讯云COS的secretKey
     * @param region    腾讯云COS存储地区
     * @param bucket    桶名称
     * @param key       对象在存储桶中的唯一标识
     */
    public static void downloadCos(String secretId, String secretKey, String region, String bucket, String key) {

        COSClient cosClient = getCosClient(secretId, secretKey, region);

        //方法1 获取下载输入流
        GetObjectRequest getObjectRequest = new GetObjectRequest(bucket, key);
        COSObject cosObject = cosClient.getObject(getObjectRequest);
        COSObjectInputStream cosObjectInput = cosObject.getObjectContent();

        //方法2 下载文件到本地
        String outputFilePath = "exampleobject";
        File downFile = new File(outputFilePath);
        getObjectRequest = new GetObjectRequest(bucket, key);
        ObjectMetadata downObjectMeta = cosClient.getObject(getObjectRequest, downFile);
    }

    /**
     * 删除对象
     *
     * @param bucket 桶名称
     * @param key    对象在存储桶中的唯一标识
     */
    public static void deleteCos(String secretId, String secretKey, String region, String bucket, String key) {
        COSClient cosClient = getCosClient(secretId, secretKey, region);
        cosClient.deleteObject(bucket, key);
    }
}
